package com.common.metric.processor;

import com.common.metric.annotation.Monitor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 扫描Bean上的@Monitor注解
 * </p>
 * @author: Sunny
 * @date: 2021/2/7
 * @version: v1.0.0
 */
@Slf4j
public class MonitorAnnotationBeanPostProcessor implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {

    private ApplicationContext applicationContext;

    private List<MonitorProcessor> processors = new ArrayList<>();

    public void addProcessor(MonitorProcessor processor) {
        processors.add(processor);
    }

    private void process(Object bean, Field field) {
        processors.forEach(processor -> processor.process(bean, field));
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        // copy from org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent
        if (event.getApplicationContext() == this.applicationContext) {
            Map<String, Object> beans = applicationContext.getBeansWithAnnotation(Monitor.class);
            for (Object bean : beans.values()) {
//                final Object aBean = AopProxyUtils.getSingletonTarget(bean);
                ReflectionUtils.doWithFields(bean.getClass(), field -> this.process(bean, field));
            }
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

}
